home *** CD-ROM | disk | FTP | other *** search
Korn shell script | 1997-08-26 | 15.2 KB | 705 lines |
- #!/bin/ksh
- # bigcal: print a big calendar
- # @(#) bigcal.ksh 2.1 96/11/13
- # 90/06 John H. DuBois III (john@armory.com)
- # 91/01/13 cleaned up slightly.
- # 95/03/23 Print help without pausing. Added description of f option to help.
- # Changed argument format.
- # 95/08/01 Added s option.
- # 96/11/13 Added X option.
-
- # Prints a calendar with squares, with digits printed in various fonts,
- # and optionally filled with data.
- # Uses 'cal' to get the digits.
- # Use -h to for help.
-
- # The output of "cal" is expected to be in a format like this:
-
- # June 1990
- # S M Tu W Th F S
- # 1 2
- # 3 4 5 6 7 8 9
- #10 11 12 13 14 15 16
- #17 18 19 20 21 22 23
- #24 25 26 27 28 29 30
-
- # Set defaults. The meaning of these vars is described in help.
- box=ascii
- t=- b=- l=\| r=\| tl=- bl=- tr=- br=- m=+ h=- v=\| # Set ascii box chars.
- hsize=9
- vsize=5
- digits=1
- ReadFields=false
- short=false
- debug=false
-
- lname=${0##*/}
- Usage=\
- "Usage: $lname [-hfs] [-b<boxtype>] [-d<digits>] [-c<name=value[,...]>]
- [-x<width>] [-y<height>] [<month>]"
-
- while getopts :fhb:d:x:y:c:sX opt; do
- case $opt in
- h)
- echo \
- "$lname: print a big (box-style) calendar.
- $Usage
- $lname prints a calendar for month <month>. <month> should be in the same
- format as that recognized by /bin/cal, except that a single numeric argument
- for month will be interpreted as a month number rather than a year, and a
- year given as two digits is assumed to be in the century 19xx. If <month>
- is not given, a calendar for the current month is printed.
- Options:
- -h: print this help.
- -s: Merge the date header into the first box line.
- -f: Read data to be printed in boxes from the standard input. The first line
- read is printed in the box for the first day of the month, etc. Each
- word on the line is printed on a separate line in the box.
- -b<boxtype>: <boxtype> should be either ascii, ibm1, or ibm2. The calendar
- boxes are printed using characters from the specified set. ascii is the
- default and will work on any ascii device. ibm1 and ibm2 look much better
- but will only work on devices that implement the IBM extended character
- set; for example, a PC console, IBM-compatible graphic printers, and Wyse
- 60 terminals.
- -d<digits>: <digits> should be one of 1, 5, ibm1_3, ibm1_5, ibm2_3, or ibm2_5.
- Date digits are drawn using the specified font. 1 is the normal
- single-character digits; 5 is a font drawn with ascii characters that is 5
- characters high; ibmn_h is a font drawn using the n-line box drawing
- characters that is h characters high. The ibmn_h fonts work on devices as
- described for box.
- -c<name=value[,...]>: Set the box drawing characters. This option should not
- be used with -b. The assignments are done by a comma-separated string of
- name=value pairs. The names and the box components they set are:
- t, b, l, r: used where a bar joins with the outer top, left, bottom, and
- right bar of the calendar.
- tl, bl, tr, br: used for the top left, bottom left, top right, and bottom
- right corner of the calendar.
- m: middle; used where a horizontal and vertical bar cross each other.
- h, v: used for drawing horizontal and vertical bars.
- -x<width>: The interior width of individual date boxes is set to <width>. The
- default is $hsize.
- -y<height>: The interior height of individual date boxes is set to <height>.
- The default is $vsize."
- exit 0
- ;;
- f)
- ReadFields=true;;
- b)
- box=$OPTARG;;
- d)
- digits=$OPTARG;;
- x)
- hsize=$OPTARG;;
- X)
- debug=true;;
- y)
- vsize=$OPTARG;;
- c)
- boxchars=$OPTARG;;
- s)
- short=true;;
- +?)
- print -u2 "$lname: options should not be preceded by a '+'."
- exit 1
- ;;
- :)
- print -u2 "$lname: Option '$OPTARG' requires a value. Use -h for help."
- exit 1
- ;;
- ?)
- print -u2 "$lname: $OPTARG: bad option. Use -h for help."
- exit 1
- ;;
- esac
- done
-
- # remove args that were options
- let OPTIND=OPTIND-1
- shift $OPTIND
-
- case $# in
- 0)
- month=`date +%h` # default month is current month
- ;;
- 1)
- month=$1
- # if month is given numerically without a year, add year to it because
- # /bin/date assumes a single numeric argument is a year.
- [[ "$month" = +([0-9]) ]] && month="$month "`date +19%y`
- ;;
- 2)
- [[ "$2" = [0-9][0-9] ]] && month="$1 19$2" || month="$*"
- ;;
- *)
- print -u2 "$Usage\nUse -h for help."
- exit 1
- ;;
- esac
-
- if [ -n "$boxchars" ]; then
- OIFS=$IFS
- IFS=,
- set -- $boxchars
- IFS=$OIFS
- for arg; do
- case $arg in
- @([tblrmhv]|[tb][lr])=*) eval ${arg%%=*}=\"${arg#*=}\";;
- esac
- done
- fi
-
- # set chars for drawing box-style digits. Names explained in help data.
- case $digits in
- ibm2_*)
- t="\0313" b="\0312" l="\0314" r="\0271" tl="\0311" bl="\0310"
- tr="\0273" br="\0274" m="\0316" h="\0315" v="\0272"
- ;;
- ibm1_*)
- t="\0302" b="\0301" l="\0303" r="\0264" tl="\0332" bl="\0300"
- tr="\0277" br="\0331" m="\0305" h="\0304" v="\0263"
- ;;
- esac
-
- # Set arrays n0..n9 and nb (blank) to digit fonts.
- # Each element of the array is a row of chars for the digit.
- # digheight is the number of rows in each digit.
- # gap is the string used to separate two digits.
- # digwidth is the width of two digits + gap
- case $digits in
- 1)
- digheight=1 digwidth=2 gap=
- n0=0 n1=1 n2=2 n3=3 n4=4 n5=5 n6=6 n7=7 n8=8 n9=9 nb=' '
- ;;
- 5)
- digheight=5 digwidth=9 gap=' '
- set -A n0 \
- ' __ ' \
- '/ \' \
- '| |' \
- '| |' \
- '\__/'
-
- set -A n1 \
- ' ' \
- ' | ' \
- ' | ' \
- ' | ' \
- ' | '
-
- set -A n2 \
- ' __ ' \
- '/ |' \
- ' / ' \
- ' / ' \
- '/___'
-
- set -A n3 \
- ' __ ' \
- '/ \' \
- ' _/' \
- ' \' \
- '\__/'
- set -A n4 \
- ' ' \
- '| | ' \
- '|_|_' \
- ' | ' \
- ' | '
-
- set -A n5 \
- '____' \
- '| ' \
- '|__ ' \
- ' \' \
- '\__/'
-
- set -A n6 \
- ' __ ' \
- '/ `' \
- '|__ ' \
- '| \' \
- '\__/'
-
- set -A n7 \
- '____' \
- ' /' \
- ' / ' \
- ' / ' \
- '/ '
-
- set -A n8 \
- ' __ ' \
- '/ \' \
- '\__/' \
- '/ \' \
- '\__/'
-
- set -A n9 \
- ' __ ' \
- '/ \' \
- '\__|' \
- ' |' \
- '\__/'
-
- set -A nb \
- ' ' \
- ' ' \
- ' ' \
- ' ' \
- ' '
- ;;
- ibm1_3|ibm2_3)
- digheight=3 digwidth=5 gap=' '
- set -A n0 -- \
- "$tl$tr" \
- "$v$v" \
- "$bl$br"
-
- set -A n1 -- \
- "$tr " \
- "$v " \
- "$b "
-
- set -A n2 -- \
- " $tr" \
- "$tl$br" \
- "$bl "
-
- set -A n3 -- \
- "$tr " \
- "$r " \
- "$br "
-
- set -A n4 -- \
- "$v$v" \
- "$bl$r" \
- " $v"
-
- set -A n5 -- \
- "$tl " \
- "$bl$tr" \
- " $br"
-
- set -A n6 -- \
- "$tl " \
- "$l$tr" \
- "$bl$br"
-
- set -A n7 -- \
- "$h$tr" \
- " $v" \
- " $v"
-
- set -A n8 -- \
- "$tl$tr" \
- "$l$r" \
- "$bl$br"
-
- set -A n9 -- \
- "$tl$tr" \
- "$bl$r" \
- " $v"
-
- set -A nb -- \
- " " \
- " " \
- " "
- ;;
- ibm1_5|ibm2_5)
- digheight=5 digwidth=7 gap=' '
- set -A n0 -- \
- "$tl$h$tr" \
- "$v $v" \
- "$v $v" \
- "$v $v" \
- "$bl$h$br"
-
- set -A n1 -- \
- " $tr " \
- " $v " \
- " $v " \
- " $v " \
- " $b "
-
- set -A n2 -- \
- " $h$tr" \
- " $v" \
- "$tl$h$br" \
- "$v " \
- "$bl$h "
-
- set -A n3 -- \
- " $h$tr" \
- " $v" \
- " $h$r" \
- " $v" \
- " $h$br"
-
- set -A n4 -- \
- "$v $v" \
- "$v $v" \
- "$bl$h$r" \
- " $v" \
- " $v"
-
- set -A n5 -- \
- "$tl$h " \
- "$v " \
- "$bl$h$tr" \
- " $v" \
- " $h$br"
-
- set -A n6 -- \
- "$tl$h " \
- "$v " \
- "$l$h$tr" \
- "$v $v" \
- "$bl$h$br"
-
- set -A n7 -- \
- "$h$h$tr" \
- " $v" \
- " $v" \
- " $v" \
- " $v"
-
- set -A n8 -- \
- "$tl$h$tr" \
- "$v $v" \
- "$l$h$r" \
- "$v $v" \
- "$bl$h$br"
-
- set -A n9 -- \
- "$tl$h$tr" \
- "$v $v" \
- "$bl$h$r" \
- " $v" \
- " $v"
-
- set -A nb -- \
- " " \
- " " \
- " " \
- " " \
- " "
- ;;
- ibm1_5w|ibm2_5w)
- digheight=5 digwidth=9 gap=' '
- set -A n0 -- \
- "$tl$h$h$tr" \
- "$v $v" \
- "$v $v" \
- "$v $v" \
- "$bl$h$h$br"
-
- set -A n1 -- \
- " $tr " \
- " $v " \
- " $v " \
- " $v " \
- " $b "
-
- set -A n2 -- \
- " $h$h$tr" \
- " $v" \
- "$tl$h$h$br" \
- "$v " \
- "$bl$h$h "
-
- set -A n3 -- \
- " $h$h$tr" \
- " $v" \
- " $h$h$r" \
- " $v" \
- " $h$h$br"
-
- set -A n4 -- \
- "$v $v" \
- "$v $v" \
- "$bl$h$h$r" \
- " $v" \
- " $v"
-
- set -A n5 -- \
- "$tl$h$h " \
- "$v " \
- "$bl$h$h$tr" \
- " $v" \
- " $h$h$br"
-
- set -A n6 -- \
- "$tl$h$h " \
- "$v " \
- "$l$h$h$tr" \
- "$v $v" \
- "$bl$h$h$br"
-
- set -A n7 -- \
- "$h$h$h$tr" \
- " $v" \
- " $v" \
- " $v" \
- " $v"
-
- set -A n8 -- \
- "$tl$h$h$tr" \
- "$v $v" \
- "$l$h$h$r" \
- "$v $v" \
- "$bl$h$h$br"
-
- set -A n9 -- \
- "$tl$h$h$tr" \
- "$v $v" \
- "$bl$h$h$r" \
- " $v" \
- " $v"
-
- set -A nb -- \
- " " \
- " " \
- " " \
- " " \
- " "
- ;;
- *)
- echo "$lname: bad value for digits: $digits. Exiting."
- exit 1
- ;;
- esac
-
- # Select box drawing characters.
- # If default (ascii) selected, chars are defaults set for ascii
- # before argument processing, unless modified during arg processing
- # by setting of t, b, etc. on command line.
- case $box in
- ascii)
- ;;
- ibm2)
- t="\0313" b="\0312" l="\0314" r="\0271" tl="\0311" bl="\0310"
- tr="\0273" br="\0274" m="\0316" h="\0315" v="\0272"
- ;;
- ibm1)
- t="\0302" b="\0301" l="\0303" r="\0264" tl="\0332" bl="\0300"
- tr="\0277" br="\0331" m="\0305" h="\0304" v="\0263"
- ;;
- *)
- echo "$lname: bad box font name $box. Exiting."
- exit 1
- ;;
- esac
-
- # printhorbar size leftchar middlechar rightchar horchar
- # Print a horizontal bar.
- # size is the interior length of each section
- # leftchar is the char to start the bar with
- # middlechar is the char to join two sections with
- # rightchar is the char to end the bar with
- # horchar is the char to draw each section with
- # 7 sections are drawn.
- # Example: the bar /---+---+---+---+---+---+---\ is generated by
- # printhorbar 3 / + '\' -
- printhorbar() {
- typeset -i i=0
- # generate bar section of specified length
- horbar=
- while [ i -lt $1 ]; do
- horbar=$horbar$5
- let i+=1
- done
- echo -n $2$horbar # print left char & first section
- i=0
- while [ i -lt 6 ]; do
- echo -n $3$horbar
- let i+=1
- done
- echo $4
- }
-
- # printver size sepchar datasize [<field1data> [... <field7data>]]
- # print a section of a rectangle
- # size is the interior (horizontal) length of each section
- # sepchar is the char to separate each section with
- # datasize is the length each data field will be after escape sequences
- # in them are resolved by "echo"
- # If it is 0, data are of various lengths, but there are no escape sequences
- # so data fields can be forced to a specific length
- printver() {
- $debug && print -ru2 -- "printver $*"
- sep=$2
- if [ $3 = 0 ]; then
- # set field var to length size+length(sep)
- typeset -L$(($1 + ${#sep})) field
- else
- # set blank padding to length size-datasize
- typeset -L$(($1 - $3)) blanks
- fi
- # size typeset does not have effect until assignment to var is made
- blanks=
- shift 3
- typeset -i i=0
- while [ i -lt 7 ]; do
- field="$sep$1"
- echo -n "$field$blanks"
- let i+=1
- [ $# -gt 0 ] && shift
- done
- echo $sep
- }
-
- # if -f given, read data for fields into d[] from stdin
- typeset -i i=1
- if $ReadFields; then
- while read d[i] && [ i -lt 32 ]; do
- let i+=1;
- done
- fi
-
- # run cal & put its output on coprocess descriptor
- cal $month |&
-
- # read month & year header from calendar
- read -p header
- if [[ "$header" = cal:* ]]; then
- echo "Bad month specified."
- exit 1
- fi
-
- typeset -i width="(hsize+1)*7+1"
- # print top bar of calendar
- if $short; then
- printhorbar $hsize $tl $t $tr $h | read line
- typeset -i i="(width-${#header})/2"
- while [ i -gt 0 ]; do
- nline=${line#?}
- print -n -- "${line%$nline}"
- line=$nline
- let i-=1
- done
- while [ -n "$header" ]; do
- nline=${header#?}
- print -n -- "${header%$nline}"
- header=$nline
- line=${line#?}
- let i-=1
- done
- print -- "$line"
- else
- # set header to be right-justified with size such that it
- # is printed at the middle of the big calendar
- typeset -R$(( (width + ${#header}) / 2 )) header
- echo "$header"
- printhorbar $hsize $tl $t $tr $h
- fi
-
- # read & discard weekday header
- read -p dateline
-
- # Print weekday header. If interior size is less than 9
- # (in which case at least Wednesday would not completely fit),
- # abbreviate all days to 3-letter prefix
- set -A days Sunday Monday Tuesday Wednesday Thursday Friday Saturday
- [ hsize -lt 9 ] && typeset -L3 days
- printver $hsize $v 0 ${days[*]}
-
- i=0
- while read -p dateline; do
- $debug && print -ru2 "Read from date: $dateline"
- # discard blank line printed by cal
- [ -z "$dateline" ] && break
-
- # count numbers in this row. If less than 7 and this is the first
- # row of numbers, set nulldates to a number of null arguments
- # equal to the difference, so that when dateline is prefixed with
- # them and converted to array the numbers will be in the correct
- # array position rather than elements 0, 1, etc.
- set $dateline
- unset nulldates
- if [ $i = 0 -a $# -lt 7 ]; then
- typeset -L$(( (7 - $#) * 3 )) nulldates
- nulldates='"" "" "" "" "" "" "" '
- fi
- eval set -A dateline $nulldates $dateline
-
- # for each day of the week, use the 0, 1 or 2 digits of the date given
- # by cal to create the digit array for the week in the chosen font.
- # nb[] (the blank digit) is used if there are less than two digits.
- # arrays wdig1n and wdig2n are the first and second digits of the date
- # for weekday n, where n is 0-6 for Sunday-Saturday.
- i=0
- IFS=:
- while [ i -lt 7 ]; do
- dt=${dateline[i]}
- case ${#dt} in
- 0)
- eval set -A wdig1$i '${nb[@]}'
- eval set -A wdig2$i '${nb[@]}';;
- 1)
- eval set -A wdig1$i -- '${n'$dt'[@]}'
- eval set -A wdig2$i '${nb[@]}';;
- 2)
- eval set -A wdig1$i -- '${n'${dt%?}'[@]}'
- eval set -A wdig2$i -- '${n'${dt#?}'[@]}';;
- esac
- $debug && eval print -ru2 -- \
- \""dt=\$dt wdig1$i=\${wdig1$i[*]} wdig2$i=\${wdig2$i[*]}"\"
- let i+=1
- done
-
- # print horizontal bar to separate calendar rectangles
- printhorbar $hsize $l $m $r $h
-
- # for each row of characters that digits are constructed from,
- # print a row of each character separated by $gap.
- # Each pair of char rows and gap becomes a data argument to printver.
- i=0
- while [ i -lt digheight ]; do
- printver $hsize $v $digwidth \
- "${wdig10[i]}$gap${wdig20[i]}" \
- "${wdig11[i]}$gap${wdig21[i]}" \
- "${wdig12[i]}$gap${wdig22[i]}" \
- "${wdig13[i]}$gap${wdig23[i]}" \
- "${wdig14[i]}$gap${wdig24[i]}" \
- "${wdig15[i]}$gap${wdig25[i]}" \
- "${wdig16[i]}$gap${wdig26[i]}"
- let i+=1
- done
-
- # Print field data & finish drawing vertical lines of boxes.
- # o[] has one element for each day of the week.
- # Each element holds the date for that day of the week.
- # The date is used as an index into d[], which holds the field data
- # for each day of the month.
- # For each line to be printed:
- # * The first word of the data for each day of the week is sent to
- # printver().
- # * That word is removed from the data.
- IFS=" "
- set -A o "${dateline[@]}"
- while [ i -lt vsize ]; do
- # eval expands the ${o[n]}'s into real indexes;
- # then ${d[n]%% *} removes all but the first word
- eval printver $hsize '$v' 0 \
- \"${d[${o[0]}]%% *}\" \"${d[${o[1]}]%% *}\" \
- \"${d[${o[2]}]%% *}\" \"${d[${o[3]}]%% *}\" \
- \"${d[${o[4]}]%% *}\" \"${d[${o[5]}]%% *}\" \
- \"${d[${o[6]}]%% *}\"
- # eval expands the ${o[n]}'s into real indexes;
- # then ${d[n]##*([! ])?( )} removes the leftmost word,
- # identified as a string of non-spaces followed by an optional
- # space (optional because the last word may not be followed by
- # a space)
- eval d[${o[0]}]=\"${d[${o[0]}]##*([! ])?( )}\" \
- d[${o[1]}]=\"${d[${o[1]}]##*([! ])?( )}\" \
- d[${o[2]}]=\"${d[${o[2]}]##*([! ])?( )}\" \
- d[${o[3]}]=\"${d[${o[3]}]##*([! ])?( )}\" \
- d[${o[4]}]=\"${d[${o[4]}]##*([! ])?( )}\" \
- d[${o[5]}]=\"${d[${o[5]}]##*([! ])?( )}\" \
- d[${o[6]}]=\"${d[${o[6]}]##*([! ])?( )}\"
- let i+=1
- done
- done
- # print bottom of calendar
- printhorbar $hsize $bl $b $br $h
-